/*
 * multiselect2side jQuery plugin
 *
 * Copyright (c) 2010 Giovanni Casassa (senamion.com - senamion.it)
 *
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://www.senamion.com
 *
 */

//optGroupSearch - 使用的OPTGROUP标签来选择元素 - 默认为false
//minSize - 最小被选择项，默认6 
//selectedPosition - 选定的元素的位置 - 默认为'右'
//moveOptions - 显示移动选项 - 默认为true
//labelTop - 顶部buttom标签 - 默认的“热门”
//labelBottom - 标签底部buttom - 默认“自下而上”
//labelUp - 高达buttom标签 - 默认'向上'
//labelDown - 下来buttom标签 - 默认“打倒” - 默认的排序排序buttom labelSort - 标签“
//maxSelected - 数量最大的可选择的选项
//labelsx：左边的标签 - 默认“*选择*'
//labeldx：右键标签 - 默认“*”
//自动排序：选择的选项自动排序 - 默认为false
//可用的选项 - 默认为false
//autoSortAvailable：自动排序 - 默认false
//添加搜索funcionality - 默认为false =没有搜索的搜索字符串
//搜索的CaseSensitive：类型 - 默认为false
//delay：延迟以毫秒为单位的延迟搜索选项后，等待一个按键来激活自身 - 默认200
(function($) {
	// SORT INTERNAL
	function internalSort(a, b) {
		var compA = $(a).text().toUpperCase();
		var compB = $(b).text().toUpperCase();
		return (compA < compB) ? -1 : (compA > compB) ? 1 : 0;
	}

	var methods = {
		init: function(options) {
			var o = {
				selectedPosition: 'right',
				moveOptions: true,
				labelTop: '置顶',
				labelBottom: '置底',
				labelUp: '向上',
				labelDown: '向下',
				labelSort: '排序',
				labelsx: '待选',
				labeldx: '已选',
				maxSelected: -1,
				autoSort: false,
				autoSortAvailable: false,
				search: false,
				caseSensitive: false,
				delay: 200,
				optGroupSearch: false,
				minSize: 6,
				labelAddSelected: "添加选择项",
				labelAddAll: "添加全部",
				labelRemoveSelected: "移除选择项",
				labelRemoveAll: "移除全部",
				labelClose: "清除搜索内容"
			};

			return this.each(function() {
				var el = $(this);
				var data = el.data('multiselect2side');

				if (options)
					$.extend(o, options);

				if (!data)
					el.data('multiselect2side', o);

				var originalName = $(this).attr("name");
				if (originalName.indexOf('[') != -1)
					originalName = originalName.substring(0, originalName.indexOf('['));

				var nameDx = originalName + "ms2side__dx";
				var nameSx = originalName + "ms2side__sx";
				var size = $(this).attr("size");
				// SIZE MIN
				if (size < o.minSize) {
					$(this).attr("size", "" + o.minSize);
					size = o.minSize;
				}

				// UP AND DOWN
				var divUpDown = "<div class='ms2side__updown'>" + "<p class='SelSort' title='Sort'>" + o.labelSort + "</p>" + "<p class='MoveTop' title='Move on top selected option'>" + o.labelTop + "</p>" + "<p class='MoveUp' title='Move up selected option'>" + o.labelUp + "</p>" + "<p class='MoveDown' title='Move down selected option'>" + o.labelDown + "</p>" + "<p class='MoveBottom' title='Move on bottom selected option'>" + o.labelBottom + "</p>" + "</div>";

				// INPUT TEXT FOR SEARCH OPTION
				var leftSearch = false, rightSearch = false;
				// BOTH SEARCH AND OPTGROUP SEARCH
				if (o.search != false && o.optGroupSearch != false) {
					var ss = o.optGroupSearch + "<select class='small' ><option value=__null__> </option></select> " + o.search + "<input class='small' type='text' /><a href='#'> </a>";

					if (o.selectedPosition == 'right')
						leftSearch = ss;
					else
						rightSearch = ss;
				} else if (o.search != false) {
					var ss = o.search + "<input type='text'/><a href='#' title='" + (o.labelClose) + "'></a>";

					if (o.selectedPosition == 'right')
						leftSearch = ss;
					else
						rightSearch = ss;
				} else if (o.optGroupSearch != false) {
					var ss = o.optGroupSearch + "<select><option value=__null__> </option></select>";

					if (o.selectedPosition == 'right')
						leftSearch = ss;
					else
						rightSearch = ss;
				}

				// CREATE NEW ELEMENT (AND HIDE IT) AFTER THE HIDDED ORGINAL
				// SELECT
				var htmlToAdd = "<div class='ms2side__div'>" + ((o.selectedPosition != 'right' && o.moveOptions) ? divUpDown : "") + "<div class='ms2side__select'>" + ((o.labelsx || leftSearch != false) ? ("<div class='ms2side__header'>" + (leftSearch != false ? leftSearch : o.labelsx) + "</div>") : "") + "<select title='" + o.labelsx + "' name='" + nameSx + "' id='" + nameSx + "' size='" + size + "' multiple='multiple' ></select>" + "</div>" + "<div class='ms2side__options'>" + ((o.selectedPosition == 'right') ? ("<p class='AddOne' title='" + (o.labelAddSelected) + "'>&rsaquo;</p>" + "<p class='AddAll' title='" + (o.labelAddAll) + "'>&raquo;</p>" + "<p class='RemoveOne' title='" + (o.labelRemoveSelected) + "'>&lsaquo;</p>" + "<p class='RemoveAll' title='" + (o.labelRemoveAll) + "'>&laquo;</p>") : ("<p class='AddOne' title='" + o.labelAddSelected + "'>&lsaquo;</p>" + "<p class='AddAll' title='" + (o.labelAddAll) + "'>&laquo;</p>" + "<p class='RemoveOne' title='" + (o.labelRemoveSelected) + "'>&rsaquo;</p>" + "<p class='RemoveAll' title='" + (o.labelRemoveAll) + "'>&raquo;</p>")) + "</div>" + "<div class='ms2side__select'>" + ((o.labeldx || rightSearch != false) ? ("<div class='ms2side__header'>" + (rightSearch != false ? rightSearch : o.labeldx) + "</div>") : "") + "<select title='" + o.labeldx + "' name='" + nameDx + "' id='" + nameDx + "' size='" + size + "' multiple='multiple' ></select>" + "</div>" + ((o.selectedPosition == 'right' && o.moveOptions) ? divUpDown : "") + "</div>";
				el.after(htmlToAdd).hide();

				// ELEMENTS
				var allSel = el.next().children(".ms2side__select").children("select");
				var leftSel = (o.selectedPosition == 'right') ? allSel.eq(0) : allSel.eq(1);
				var rightSel = (o.selectedPosition == 'right') ? allSel.eq(1) : allSel.eq(0);
				// HEIGHT DIV
				var heightDiv = $(".ms2side__select").eq(0).height();

				// SELECT optgroup
				var searchSelect = $();

				// SEARCH INPUT
				var searchInput = $(this).next().find("input:text");
				var removeFilter = searchInput.next().hide();
				var toid = false;
				var searchV = false;

				// SELECT optgroup - ADD ALL OPTGROUP AS OPTION
				if (o.optGroupSearch != false) {
					var lastOptGroupSearch = false;

					searchSelect = $(this).next().find("select").eq(0);

					el.children("optgroup").each(function() {
						if (searchSelect.find("[value='" + $(this).attr("label") + "']").size() == 0)
							searchSelect.append("<option value='" + $(this).attr("label") + "'>" + $(this).attr("label") + "</option>");
					});
					searchSelect.change(function() {
						var sEl = $(this);

						if (sEl.val() != lastOptGroupSearch) {

							// IF EXIST SET SEARCH TEXT TO VOID
							if (searchInput.val() != "") {
								clearTimeout(toid);
								removeFilter.hide();
								searchInput.val("");// .trigger('keyup');
								searchV = "";
								// fto();
							}

							setTimeout(function() {
								if (sEl.val() == "__null__") {
									els = el.find("option:not(:selected)");
								} else
									els = el.find("optgroup[label='" + sEl.val() + "']").children("option:not(:selected)");

								// REMOVE ORIGINAL ELEMENTS AND ADD OPTION OF
								// OPTGROUP SELECTED
								leftSel.find("option").remove();
								els.each(function() {
									leftSel.append($(this).clone());
								});
								lastOptGroupSearch = sEl.val();
								leftSel.trigger('change');
							}, 100);
						}
					});
				}

				// SEARCH FUNCTION
				var fto = function() {
					var els = leftSel.children();
					var toSearch = el.find("option:not(:selected)");

					// RESET OptGroupSearch
					lastOptGroupSearch = "__null__";
					searchSelect.val("__null__");

					if (searchV == searchInput.val())
						return;

					searchInput.addClass("wait").removeAttr("style");

					searchV = searchInput.val();

					// A LITTLE TIMEOUT TO VIEW WAIT CLASS ON INPUT ON IE
					setTimeout(function() {
						leftSel.children().remove();
						if (searchV == "") {
							toSearch.clone().appendTo(leftSel).removeAttr("selected");
							removeFilter.hide();
						} else {
							toSearch.each(function() {
								var myText = $(this).text();

								if (o.caseSensitive)
									find = myText.indexOf(searchV);
								else
									find = myText.toUpperCase().indexOf(searchV.toUpperCase());

								if (find != -1)
									$(this).clone().appendTo(leftSel).removeAttr("selected");
							});

							if (leftSel.children().length == 0)
								searchInput.css({
									'border': '1px red solid'
								});

							removeFilter.show();
							leftSel.trigger('change');
						}
						leftSel.trigger('change');
						searchInput.removeClass("wait");
					}, 5);
				};

				// REMOVE FILTER ON SEARCH FUNCTION
				removeFilter.click(function() {
					clearTimeout(toid);
					searchInput.val("");
					fto();
					return false;
				});

				// ON CHANGE TEXT INPUT
				searchInput.keyup(function() {
					clearTimeout(toid);
					toid = setTimeout(fto, o.delay);
				});

				// CENTER MOVE OPTIONS AND UPDOWN OPTIONS
				$(this).next().find('.ms2side__options, .ms2side__updown').each(function() {
					var top = ((heightDiv / 2) - ($(this).height() / 2));
					if (top > 0)
						$(this).css('padding-top', top + 'px');
				})

				// MOVE SELECTED OPTION TO RIGHT, NOT SELECTED TO LEFT
				$(this).find("option:selected").clone().appendTo(rightSel); // .removeAttr("selected");
				$(this).find("option:not(:selected)").clone().appendTo(leftSel);

				// 判断浏览器类型
				$.browser = {};
				$.browser.mozilla = /firefox/.test(navigator.userAgent.toLowerCase());
				$.browser.webkit = /webkit/.test(navigator.userAgent.toLowerCase());
				$.browser.opera = /opera/.test(navigator.userAgent.toLowerCase());
				$.browser.msie = /msie/.test(navigator.userAgent.toLowerCase());

				// SELECT FIRST LEFT ITEM AND DESELECT IN RIGHT (NOT IN IE6)
				if (!($.browser.msie && $.browser.version == '6.0')) {
					leftSel.find("option").eq(0).attr("selected", true);
					rightSel.children().removeAttr("selected");
				}

				// ON CHANGE SORT SELECTED OPTIONS
				var nLastAutosort = 0;
				if (o.autoSort)
					allSel.change(function() {
						var selectDx = rightSel.find("option");

						if (selectDx.length != nLastAutosort) {
							// SORT SELECTED ELEMENT
							selectDx.sort(internalSort);
							// FIRST REMOVE FROM ORIGINAL SELECT
							el.find("option:selected").remove();
							// AFTER ADD ON ORIGINAL AND RIGHT SELECT
							selectDx.each(function() {
								rightSel.append($(this).clone());
								$(this).appendTo(el).attr("selected", true);
								// el.append($(this).attr("selected", true));
								// HACK IE6
							});
							nLastAutosort = selectDx.length;
						}
					});

				// ON CHANGE SORT AVAILABLE OPTIONS (NOT NECESSARY IN ORIGINAL
				// SELECT)
				var nLastAutosortAvailable = 0;
				if (o.autoSortAvailable)
					allSel.change(function() {
						var selectSx = leftSel.find("option");

						if (selectSx.length != nLastAutosortAvailable) {
							// SORT SELECTED ELEMENT
							selectSx.sort(internalSort);
							// REMOVE ORIGINAL ELEMENTS AND ADD SORTED
							leftSel.find("option").remove();
							selectSx.each(function() {
								leftSel.append($(this).clone());
							});
							nLastAutosortAvailable = selectSx.length;
						}
					});

				// ON CHANGE REFRESH ALL BUTTON STATUS
				allSel.change(function() {
					// HACK FOR IE6 (SHOW AND HIDE ORIGINAL SELECT)
					if ($.browser.msie && $.browser.version == '6.0')
						el.show().hide();
					var div = $(this).parent().parent();
					var selectSx = leftSel.children();
					var selectDx = rightSel.children();
					var selectedSx = leftSel.find("option:selected");
					var selectedDx = rightSel.find("option:selected");

					if (selectedSx.size() == 0 || (o.maxSelected >= 0 && (selectedSx.size() + selectDx.size()) > o.maxSelected))
						div.find(".AddOne").addClass('ms2side__hide');
					else
						div.find(".AddOne").removeClass('ms2side__hide');

					// FIRST HIDE ALL
					div.find(".RemoveOne, .MoveUp, .MoveDown, .MoveTop, .MoveBottom, .SelSort").addClass('ms2side__hide');
					if (selectDx.size() > 1)
						div.find(".SelSort").removeClass('ms2side__hide');
					if (selectedDx.size() > 0) {
						div.find(".RemoveOne").removeClass('ms2side__hide');
						// ALL SELECTED - NO MOVE
						if (selectedDx.size() < selectDx.size()) { // FOR NOW
							// (JOE) &&
							// selectedDx.size()
							// == 1
							if (selectedDx.val() != selectDx.val()) // FIRST
								// OPTION,
								// NO UP AND
								// TOP
								// BUTTON
								div.find(".MoveUp, .MoveTop").removeClass('ms2side__hide');
							if (selectedDx.last().val() != selectDx.last().val()) // LAST
								// OPTION,
								// NO
								// DOWN
								// AND
								// BOTTOM
								// BUTTON
								div.find(".MoveDown, .MoveBottom").removeClass('ms2side__hide');
						}
					}

					if (selectSx.size() == 0 || (o.maxSelected >= 0 && selectSx.size() >= o.maxSelected))
						div.find(".AddAll").addClass('ms2side__hide');
					else
						div.find(".AddAll").removeClass('ms2side__hide');

					if (selectDx.size() == 0)
						div.find(".RemoveAll").addClass('ms2side__hide');
					else
						div.find(".RemoveAll").removeClass('ms2side__hide');
				});

				// DOUBLE CLICK ON LEFT SELECT OPTION
				leftSel.dblclick(function() {
					$(this).find("option:selected").each(function(i, selected) {

						if (o.maxSelected < 0 || rightSel.children().size() < o.maxSelected) {
							$(this).remove().appendTo(rightSel);
							el.find("[value='" + $(selected).val() + "']").remove().appendTo(el).attr("selected", true);
						}
					});
					$(this).trigger('change');
				});

				// DOUBLE CLICK ON RIGHT SELECT OPTION
				rightSel.dblclick(function() {
					$(this).find("option:selected").each(function(i, selected) {
						$(this).remove().appendTo(leftSel);
						el.find("[value='" + $(selected).val() + "']").removeAttr("selected").remove().appendTo(el);
					});
					$(this).trigger('change');

					// TRIGGER CHANGE AND VALUE NULL FORM OPTGROUP SEARCH (IF
					// EXIST)
					searchSelect.val("__null__").trigger("change");
					// TRIGGER CLICK ON REMOVE FILTER (IF EXIST)
					removeFilter.click();
				});

				// CLICK ON OPTION
				$(this).next().find('.ms2side__options').children().click(function() {
					if (!$(this).hasClass("ms2side__hide")) {
						if ($(this).hasClass("AddOne")) {
							leftSel.find("option:selected").each(function(i, selected) {
								$(this).remove().appendTo(rightSel);
								el.find("[value='" + $(selected).val() + "']").remove().appendTo(el).attr("selected", true);
							});
						} else if ($(this).hasClass("AddAll")) { // ALL
							// SELECTED
							// TEST IF HAVE A FILTER OR A SELECT OPTGROUP
							if (removeFilter.is(":visible") || (searchSelect.length > 0 && searchSelect.val() != "__null__"))
								leftSel.children().each(function(i, selected) {
									$(this).remove().appendTo(rightSel);
									el.find("[value='" + $(selected).val() + "']").remove().appendTo(el).attr("selected", true);
								});
							else {
								leftSel.children().remove().appendTo(rightSel);
								el.find('option').attr("selected", true);
								// el.children().attr("selected", true); --
								// PROBLEM WITH OPTGROUP
							}
						} else if ($(this).hasClass("RemoveOne")) {
							rightSel.find("option:selected").each(function(i, selected) {
								$(this).remove().appendTo(leftSel);
								el.find("[value='" + $(selected).val() + "']").remove().appendTo(el).removeAttr("selected");
							});
							// TRIGGER CLICK ON REMOVE FILTER (IF EXIST)
							removeFilter.click();
							// TRIGGER CHANGE AND VALUE NULL FORM OPTGROUP
							// SEARCH (IF EXIST)
							searchSelect.val("__null__").trigger("change");
						} else if ($(this).hasClass("RemoveAll")) { // ALL
							// REMOVED
							rightSel.children().appendTo(leftSel);
							rightSel.children().remove();
							el.find('option').removeAttr("selected");
							// el.children().removeAttr("selected"); -- PROBLEM
							// WITH OPTGROUP
							// TRIGGER CLICK ON REMOVE FILTER (IF EXIST)
							removeFilter.click();
							// TRIGGER CHANGE AND VALUE NULL FORM OPTGROUP
							// SEARCH (IF EXIST)
							searchSelect.val("__null__").trigger("change");
						}
					}

					leftSel.trigger('change');
				});

				// CLICK ON UP - DOWN
				$(this).next().find('.ms2side__updown').children().click(function() {
					var selectedDx = rightSel.find("option:selected");
					var selectDx = rightSel.find("option");

					if (!$(this).hasClass("ms2side__hide")) {
						if ($(this).hasClass("SelSort")) {
							// SORT SELECTED ELEMENT
							selectDx.sort(internalSort);
							// FIRST REMOVE FROM ORIGINAL SELECT
							el.find("option:selected").remove();
							// AFTER ADD ON ORIGINAL AND RIGHT SELECT
							selectDx.each(function() {
								rightSel.append($(this).clone().attr("selected", true));
								el.append($(this).attr("selected", true));
							});
						} else if ($(this).hasClass("MoveUp")) {
							var prev = selectedDx.first().prev();
							var hPrev = el.find("[value='" + prev.val() + "']");

							selectedDx.each(function() {
								$(this).insertBefore(prev);
								el.find("[value='" + $(this).val() + "']").insertBefore(hPrev); // HIDDEN
								// SELECT
							});
						} else if ($(this).hasClass("MoveDown")) {
							var next = selectedDx.last().next();
							var hNext = el.find("[value='" + next.val() + "']");

							selectedDx.each(function() {
								$(this).insertAfter(next);
								el.find("[value='" + $(this).val() + "']").insertAfter(hNext); // HIDDEN
								// SELECT
							});
						} else if ($(this).hasClass("MoveTop")) {
							var first = selectDx.first();
							var hFirst = el.find("[value='" + first.val() + "']");

							selectedDx.each(function() {
								$(this).insertBefore(first);
								el.find("[value='" + $(this).val() + "']").insertBefore(hFirst); // HIDDEN
								// SELECT
							});
						} else if ($(this).hasClass("MoveBottom")) {
							var last = selectDx.last();
							var hLast = el.find("[value='" + last.val() + "']");

							selectedDx.each(function() {
								last = $(this).insertAfter(last); // WITH last
								// = SAME POSITION OF SELECTED OPTION AFTER MOVE
								hLast = el.find("[value='" + $(this).val() + "']").insertAfter(hLast); // HIDDEN
								// SELECT
							});
						}
					}

					leftSel.trigger('change');
				});

				// HOVER ON OPTION
				$(this).next().find('.ms2side__options, .ms2side__updown').children().hover(function() {
					$(this).addClass('ms2side_hover');
				}, function() {
					$(this).removeClass('ms2side_hover');
				});

				// UPDATE BUTTON ON START
				leftSel.trigger('change');
				// SHOW WHEN ALL READY
				$(this).next().show();
			});
		},
		destroy: function() {
			return this.each(function() {
				var el = $(this);
				var data = el.data('multiselect2side');

				if (!data)
					return;

				el.show().next().remove();
			});
		},
		addOption: function(options) {
			var oAddOption = {
				name: false,
				value: false,
				selected: false
			};

			return this.each(function() {
				var el = $(this);
				var data = el.data('multiselect2side');

				if (!data)
					return;

				if (options)
					$.extend(oAddOption, options);

				var strEl = "<option value='" + oAddOption.value + "' " + (oAddOption.selected ? "selected" : "") + " >" + oAddOption.name + "</option>";

				el.append(strEl);

				// ELEMENTS
				var allSel = el.next().children(".ms2side__select").children("select");
				var leftSel = (data.selectedPosition == 'right') ? allSel.eq(0) : allSel.eq(1);
				var rightSel = (data.selectedPosition == 'right') ? allSel.eq(1) : allSel.eq(0);

				if (oAddOption.selected)
					rightSel.append(strEl).trigger('change');
				else
					leftSel.append(strEl).trigger('change');
			});
		},
		/**
		 * 批量添加数据
		 * 
		 * @param options
		 * 
		 */
		addOptions: function(options) {
			var oAddOption = {
				name: undefined,
				value: undefined,
				selected: false
			};

			return this.each(function() {
				var el = $(this);
				var data = el.data('multiselect2side');

				if (!data) {
					return;
				}

				// ELEMENTS
				var allSel = el.next().children(".ms2side__select").children("select");
				var leftSel = (data.selectedPosition == 'right') ? allSel.eq(0) : allSel.eq(1);
				var rightSel = (data.selectedPosition == 'right') ? allSel.eq(1) : allSel.eq(0);

				if (options) {
					if ($.isArray(options) == false) {
						options = [options];
					}

					for (var i = 0; i < options.length; i++) {
						var option = {
							name: undefined,
							value: undefined,
							selected: false
						};
						$.extend(option, options[i]);
						if (option.value == undefined) {
							continue;
						}

						var strEl = "<option value='" + option.value + "' " + (option.selected ? "selected" : "") + " >" + option.name + "</option>";

						var condition = "option[value='" + option.value + "']";

						if (el.find(condition).size() > 0) {
							el.find(condition).attr("name", option.name);
							el.find(condition).prop("selected", option.selected);
						} else {
							el.append(strEl);
						}

						if (option.selected) {
							if (leftSel.find(condition).size() > 0) {
								leftSel.find(condition).remove();
							}
							if (rightSel.find(condition).size() == 0) {
								rightSel.append(strEl).trigger('change');
							}
						} else {
							if (rightSel.find(condition).size() > 0) {
								rightSel.find(condition).remove();
							}
							if (leftSel.find(condition).size() == 0) {
								leftSel.append(strEl).trigger('change');
							}
						}
					}
				}

			});
		},
		/**
		 * 移除所有未选择的项，便于添加AJAX查询的数据
		 */
		removeUnSelected: function() {
			return this.each(function() {
				var el = $(this);
				var data = el.data('multiselect2side');

				if (!data)
					return;

				// ELEMENTS
				var allSel = el.next().children(".ms2side__select").children("select");

				if (data.selectedPosition == 'right') {
					allSel.eq(0).empty();
				} else {
					allSel.eq(1).empty();
				}

			});
		},
		values: function(){
			var el = $(this);
			var data = el.data('multiselect2side');

			if (!data){
				return;
			}

			// ELEMENTS
			var allSel = el.next().children(".ms2side__select").children("select");

			var values = [];
			var i = 0;
			
			if (data.selectedPosition == 'right') {
				i = 1;
			}

			allSel.eq(i).find("option").each(function(){
				values.push($(this).val());
			});
			
			return values;
		}
	};

	$.fn.multiselect2side = function(method) {
		if (methods[method]) {
			return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
		} else if (typeof method === 'object' || !method) {
			return methods.init.apply(this, arguments);
		} else {
			$.error('Method ' + method + ' does not exist on jQuery.multiselect2side');
		}
	};
})(jQuery);